"""
Librosa实现类
基于librosa的声纹识别实现
"""

import hashlib
from typing import Tuple, Dict, Any

import librosa
import numpy as np

# 导入声纹识别实现基类
from .base import VoiceprintImplementation
# 导入返回码枚举
from ...constants.return_codes import BaseCodeEnum, ReturnCode
# 导入日志工具
from ...utils.logger import get_logger


class LibrosaImplementation(VoiceprintImplementation):
    """
    基于librosa的声纹识别实现
    """

    # 默认参数配置
    DEFAULT_CONFIG = {
        'sr': 22050,  # 采样率
        'n_mfcc': 13,  # MFCC特征维度
        'n_fft': 2048,  # FFT窗口大小
        'hop_length': 512,  # 跳跃长度
        'max_pad_len': 174,  # 最大填充长度
    }

    def __init__(self, config: Dict[str, Any] = None):
        """
        初始化Librosa实现
        
        Args:
            config: 配置参数，如果为None则使用默认配置
        """
        # 设置配置参数
        self.config = config or self.DEFAULT_CONFIG.copy()
        # 初始化日志记录器
        self.logger = get_logger(__name__)

    def extract_voiceprint(self, audio_file: str, **kwargs) -> Tuple[BaseCodeEnum, Dict[str, Any]]:
        """
        使用librosa提取音频的声纹特征
        
        Args:
            audio_file: 音频文件路径
            **kwargs: 扩展参数
            
        Returns:
            Tuple[int, str, Dict[str, Any]]: (状态码, 声纹ID, 结果信息)
        """
        self.logger.info(f"开始提取声纹特征: audio_file={audio_file}")
        try:
            # 加载音频文件
            y, sr = librosa.load(audio_file, sr=self.config['sr'])

            # 提取MFCC特征
            mfcc = librosa.feature.mfcc(
                y=y,
                sr=sr,
                n_mfcc=self.config['n_mfcc'],
                n_fft=self.config['n_fft'],
                hop_length=self.config['hop_length']
            )

            # 标准化特征
            mfcc = (mfcc - np.mean(mfcc)) / np.std(mfcc)

            # 处理特征长度
            if mfcc.shape[1] > self.config['max_pad_len']:
                # 截断过长的特征
                mfcc = mfcc[:, :self.config['max_pad_len']]
            else:
                # 填充过短的特征
                pad_width = self.config['max_pad_len'] - mfcc.shape[1]
                mfcc = np.pad(mfcc, ((0, 0), (0, pad_width)), mode='constant')

            # 将特征展平为一维向量
            features = mfcc.flatten()

            # 生成声纹ID（使用MD5哈希）
            features_str = ','.join(map(str, features))
            voiceprint_id = hashlib.md5(features_str.encode()).hexdigest()

            self.logger.info(f"声纹特征提取完成: voiceprint_id={voiceprint_id}")

            # 构建结果信息
            result_info = {
                "audio_file": audio_file,
                "duration": len(y) / sr,
                "sample_rate": sr,
                "features_shape": mfcc.shape,
                "feature_length": len(features),
                "voiceprint_id": voiceprint_id,
                "extracted_features": features.tolist()  # 转换为列表便于序列化
            }

            return ReturnCode.SUCCESS, result_info

        except Exception as e:
            # 提供更详细的错误信息
            error_msg = f"声纹特征提取失败: {str(e)}"
            if "NoBackendError" in str(e):
                error_msg += " (可能是音频格式不支持或缺少解码器)"
            elif "MemoryError" in str(e):
                error_msg += " (可能是内存不足，尝试处理更短的音频)"

            self.logger.error(error_msg)
            raise e

    def get_feature_info(self) -> Dict[str, Any]:
        """
        获取特征提取信息
        
        Returns:
            Dict[str, Any]: 包含特征维度、提取算法等信息的字典
        """
        # 返回特征提取算法信息
        return {
            "algorithm": "MFCC",
            "feature_type": "mel-frequency cepstral coefficients",
            "feature_dimension": self.config['n_mfcc'] * self.config['max_pad_len'],
            "config": self.config,
            "extraction_method": "librosa.feature.mfcc"
        }

    def compare_voiceprints(self, voiceprint1: str, voiceprint2: str) -> Tuple[float, Dict[str, Any]]:
        """
        比较两个声纹特征的相似度
        
        Args:
            voiceprint1: 第一个声纹特征（MD5哈希值）
            voiceprint2: 第二个声纹特征（MD5哈希值）
            
        Returns:
            Tuple[float, Dict[str, Any]]: (相似度分数, 比较结果信息)
        """
        # 验证输入
        if not voiceprint1 or not voiceprint2:
            return 0.0, {"error": "声纹特征不能为空"}

        # 简单的哈希值比较（完全匹配为1.0，不匹配为0.0）
        # 在实际应用中，这里应该比较实际的特征向量
        similarity = 1.0 if voiceprint1 == voiceprint2 else 0.0

        # 构建比较结果信息
        result_info = {
            "voiceprint1": voiceprint1,
            "voiceprint2": voiceprint2,
            "similarity": similarity,
            "match": similarity == 1.0,
            "note": "当前实现使用简单哈希比较，实际应用中应比较特征向量"
        }

        return similarity, result_info
